/*
 *  Copyright (C) 2007 Veit Wehner.
 *  All Rights Reserved.
 *
 *  This is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This software is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this software; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
 *  USA.
 */


/** \file sw_update.h
 * \brief Main header file.           
 * \author Veit Wehner <veit.wehner@gmail.com>
 */
 
 
#ifndef __swupdate__
#define __swupdate__



//#######################CONFIGURATION#####################################################
/// Set RECEIVE_PROTOCOLL to either UART or ETHERNET _for_ the _Injektor__Node_		//#
/// Set RECEIVE_PROTOCOLL to YANET _for_  _any_ other node				//#
#define RECEIVE_PROTOCOLL YANET
/// Set __either__ ENCRYPTION to TEA for a block cypher __or__ 				//#
/// __or__ HASH_CHECKSUM to DAVIES_MEYER for a cryptographic checksum			//#
#define ENCRYPTION 0
#define HASH_CHECKSUM 0

#define INJECTOR_NODE_ID 0x0118
#define CLONING_ENABLED 1
/**											//#
 * @name Debug and simulation modes							//#
 * 											//#
 */											//#
//@{											//#
/// Modus for testing the injector node 						//#
/// no forwarding to the destination node						//#
#define TEST 0					
/// Debug output by the SHOW Macro							//#
/// _DO_ _NOT_ _ENABLE_ _DEBUG_ _WITH_ _UART_ _AND_ _THE_ _INJECTOR_ _NODE_  
#define DEBUG 0
/// Simulation of reprogramming flash;							//#
/// Flash write simulation								//#
#define DEBUG_2 0
/// Set this TESTCASE to POWER_LOSS for a Simulation of a Power 			//#
/// Loss during Reprogramming								//#
/// in order to show the Recovery mechanism.						//#
/// For normal usage set TESTCASE to 0.							//#
#define TESTCASE 0									
#define FILE_FOR_CLONING 10
#define DEFAULT_HEADER_FILE 2
#define DEFAULT_SEGMENT_FILE 3
//#########################################################################################

#include <io.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <kernel/kernel.h>
#include <lib/uarts.h>
#include <lib/sysclk.h>
#include <lib/at45fs.h>
#include <lib/infomem.h>
#include <lib/YaNET.h>
//#include "sha1.h"

#define VERIFIED 0
#define WRONG 1
#define RECOVERY_SEGMENT_ERROR	1
#define RECOVERY_SEGMENT_SUCCESS 0
#if !defined(__lint__)
#define __NORETURN__	for (;;) continue
#else
#define __NORETURN__
#endif

/**
 * @name Program image properties 
 */
//@{
/// max valid number of segments/required 
/// file system blocks for the image
/// better than using malloc on runtime
#define MAXSEGMENTCOUNT 		10
#define MAXBLOCKCOUNT 			40
#define FLASH_BLOCKSIZE 2
/// contains filenumbers pointing to 
/// the two files wich contain the 
/// image header and the segment data 
#define FILE_FOR_FILE 1
//#define FILE_FOR_VIRTUAL_SEGMENT 10
//}
/// 
#define CHUNKSIZE 32
#define RAM_REQUIREMENT 1600 //for the reprogr. routine
#define TEA 1
#define SHA1 2
#define CRC16 3
#define DAVIES_MEYER 4


#define SAFETY 0//DAVIES_MEYER
#define KEY_LENGTH 4
#define HASH_LENGTH 2
#define FORWARDING_ENABLED 1

#define POWER_LOSS 1
#define INTERRUPT_VECTOR_LOCATION 0xffe0
#define NONE 4
#define SIG_UNKNOWN 12
#define FLASH 15
#define UART 16
#define YANET 17
#define ETHERNET 18
#define INVALID -42
#define FORWARDING_ENABLED 1
#define UPDATE 50
#define JUST_STORE_AN_IMAGE 51
#define RESTORE_EXECUTE_AN_IMAGE 52
#define CLONE 53
#define INIT 3
#if RECEIVE_PROTOCOLL==ETHERNET
#include <lib/tcpip.h>
#endif

/*
  #if DEBUG
  #define SHOW_HEX(x)     getResource(&UART_RESOURCE);printf(#x ": %2x\n", x);releaseResource(&UART_RESOURCE)
  #define SHOW_HEX_WORD(x)    getResource(&UART_RESOURCE); printf(#x ": %04x\n", x);releaseResource(&UART_RESOURCE)
  #define SHOW_DEC(x)     getResource(&UART_RESOURCE);printf(#x ": %d\n", x);releaseResource(&UART_RESOURCE)
  #define SHOW_ADR(x)    getResource(&UART_RESOURCE); printf(#x ": %p\n", x);releaseResource(&UART_RESOURCE)
  #define SHOW(x)     getResource(&UART_RESOURCE);printf(#x"\n");releaseResource(&UART_RESOURCE)
*/


enum sig_op {
  sig, 
  remove_sig
};

#if DEBUG
#define SHOW_HEX(x)   printf(#x ": %2x\n", x)
#define SHOW_HEX_WORD(x)    printf(#x ": %04x\n", x)
#define SHOW_DEC(x)     printf(#x ": %d\n", x)
#define SHOW_ADR(x)     printf(#x ": %p\n", x)
#define SHOW(x)     printf(#x"\n")
#else 
#define SHOW_HEX(x) 
#define SHOW_HEX_WORD(x)
#define SHOW_DEC(x)
#define SHOW(x)
#define SHOW_ADR(x)
#endif    



struct elf{
  int nr;
  /*! The number of segments from the memory view */
  unsigned int start_addresses[MAXSEGMENTCOUNT];
  /*!< Array containing the start addresses of the segments */
  unsigned char reset_vec_adr[2];
  /*!< This saves the reset_vector address wich is 
   *  interchanged with the recovery routine 
   * temporarily during reprogramming  */
  unsigned int lengths[MAXSEGMENTCOUNT];
  /*!< Array containing the lengths of the segments */
  unsigned int elf_size;
  /*!< Total image size. Sum of all segments. 
   * Finally, the size of the recovery segment is added.
   */
  unsigned int size_of_routine;
  /*!< Size of recovery segment 
   * ( ~ size (reprogramming functions) ) 
   */
  unsigned int block_list[MAXBLOCKCOUNT];
  /*!<  List of filesystsem blocks wich hold the segment data*/
  int no_of_used_blocks;
  /*!< Number of filesystem blocks associated with 
   * the file for the image data ( <= MAXBLOCKCOUNT )
   */
  int segment_counter;
  /*!< Counter of the actual segment ( <= MAXSEGMENTCOUNT )
   * used while reading writing segment data. Annotation:
   * reading and writing are general functions of the above layer.
   */
#if CLONING_ENABLED
  unsigned int inner_segment_counter;
  /*!< ONLY needed when genotype is read from internal flash 
   * during cloning. In case of the memory efficient UPDATE_MODE SWUPDATE2
   * ( please read the thesis for details ) genotype is 
   * retreived from the external flash.
   * This additional counter is necessary to avoid changes in the 
   * "Schichtenmodell". That makes the way of retreiving the image data
   * during cloning consistent with all the other ways/modes.
   */
  unsigned char  wich_word; 
  /*!< Only used in UPDATE_MODE == SWUPDATE1 
   * for getting the genotype during cloning.
   * This additional counter is necessary to avoid changes in the 
   * "Schichtenmodell". That makes the way of retreiving the image data
   * during cloning consistent with all the other ways/modes.
   */
#endif
  
};



struct scratch_status{
  int bytes_left_to_read;
  /*!< Decrementing counter during reprogramming: 
   * Number of image data bytes still remaining
   */
  
  int actual_segment_data_count;
  /*!< Incrementing data counter of one memory segment. 
   */
  int actual_segment_nr;
  /*!< Counter of the actual memory segment during reprogramming */
  int block_counter;
  /*!< Incrementing counter up to elfe->no_of_used_blocks */
  int page_counter;
  /*!<  A block on the AT45DB161B consists of two pages.
   * => ( page_counter == 0) | ( page_counter = 1) 
   */
};




struct communication{
  unsigned char acknowledgment;
  /*!<  */
  unsigned short communication_partner;
  /*!<  */
  unsigned short packet_loss_count;
  /*!<  */
#if (RECEIVE_PROTOCOLL==UART)||DEBUG
  uart_device_t *uart;
  /*!<  */
#endif
#if RECEIVE_PROTOCOLL==ETHERNET
  Connection_t *con;
  /*!<  */
  TranceiveVector_t *tv;
#endif
};



struct swupdate{
  struct communication *communice;
  /*!< Pointer to the communication instance */
  struct elf *elfe;
  /*!< Pointer to the program image instance */
  unsigned short src_node_id;
  /*!<  ID of the node sending the program image 
   *  corresponding to the update command. This is 
   *  most often zero when the program image is 
   *  generated by the computer. 
   *  It might also be the ID of a node who wants 
   *  to clone himself.
   */
  unsigned short dst_node_id;
  /*!<  ID of the node receiving the update command.
   *  It is compared to the own node ID in the infomem
   *  to know wich role the node plays in the command chain.
   */
  unsigned short own_node_id;
  /*!<  
   *  This ID is stored at a fixed address in the infomem.
   */
  unsigned char update_command;
  /*!< UPDATE and ADDIMAGE are the only remote control commands.
   * They are quite orthogonal and
   * minimalistic, but provide all the functionality if combined 
   * with other command parameters ( especially the src and dst node ids ).
   * Please refer to the manual or
   * the command line help in the python script for more information.
   */
  int file_for_segment_data;
  int file_for_image_header; 
  /*!<  
   *If a node needs to be reprogrammed,
   * one file is specified to store
   * the image header information extracted from
   * the ELF file and transmitted afterwards.
   * In the other file the binary data of the memory
   * image shall be stored later.
   *
   * Otherwise, if an existing image ( existing on the
   * external flash of a node ) is to be restored, the
   * files point to existing files. Then, no program image
   * will be transmitted.
   */
  
  
  unsigned char priv_data_buf[CHUNKSIZE];
  /*!< This buffer holds the data wich was read before 
   * and is now ready for further processing ( writing ).
   * Annotation:
   * reading and writing are general functions of the above layer. 
   */
  int datalen;
  /*!< The fill level of priv_data_buf.
   */ 
  int priv_word;
  /*!< This buffer holds the word (i.e. an address, a length, a node ID,
   * the update command itsself etc. )
   * wich was read before 
   * and is now ready for further processing ( writing ).
   * Annotation:
   * reading and writing are general functions of the above layer. 
   */
  
  int out_of_order_diff;
  /*!<  The number of packets missed out when 
   *  a so called Out-of-Order Arrival occured.
   */


  /*!<  These are the abstract methods of the remote 
   *  ipdate protocol. See the documentation for details.
   */  
  int (*wait_for_update_signal)(void);
  void (*read_word)(struct swupdate*);
  void (*read)(struct swupdate*);
  void (*send_sync)(struct swupdate*);
  void (*wait_for_sync)(struct swupdate*);
  void (*write_word)(struct swupdate*);
  void (*write)(struct swupdate*);
  
};

typedef struct {
  unsigned char base;
  unsigned char mask;
} GPIOPin_t_;

typedef struct {
  GPIOPin_t_ pin_cs;
} SPIDevice_t_;




/**
 * This function is just a workaround due to an existing bug in the linker script,
 * As the hole library in the resource path will not be included if theres no call 
 * to a function in it. A Task in the lib doesn't change it. 
 * The init function accesses a global volatile variable, so it can't be left out
 * by any linker optimization.
 */
extern void init_sw_update(void);


/**
 * This function tranmits a chunk of data via YaNET to another node
 * if it is referenced by the write function of the swupdate object.
 * @param transmit data
 * @param data length
 * @swupdate instance containing other information
 * (encryption mode, communication partner ..)
 */
extern void transmit(unsigned char*, int, struct swupdate*, int);



/**
 * This function sends a sync packet to the communication partner node
 * if it is referenced by the sync function of the swupdate object.
 * @param swupdate instance
 */
extern void send_sync(struct swupdate*);



/**
 * This function waits for a sync packet from the communication partner node
 * if it is referenced by the wait function of the swupdate object.
 * @param swupdate instance
 */
extern void wait_for_remote_node(struct swupdate*);



/**
 * This function receives a packet via YaNET 
 * ( of word length, chunksize, whatever ).
 * @param swupdate instance
 */
extern void receive(void);



/**
 * This function receives a short packet
 * from the communication partner node via YaNET
 * if it is referenced by the read_word function of the swupdate object.
 * @param swupdate instance
 */
extern void yanet_read_word(struct swupdate*);


/**
 * This function receives a packet ( containing a chunk of data ) 
 * from the communication partner node via YaNET
 * if it is referenced by the read function of the swupdate object.
 * @param swupdate instance
 */
extern void yanet_read(struct swupdate*);

extern void image_header_read_word(struct swupdate*);

extern void program_memory_read(struct swupdate*);

extern void at45fs_read(struct swupdate*);


/**
 * This function transmits a short packet
 * to the communication partner node via YaNET
 * if it is referenced by the write_word function of the swupdate object.
 * @param swupdate instance
 */
extern void yanet_write_word(struct swupdate*);



/**
 * This function transmits a packet
 * to the communication partner node via YaNET
 * if it is referenced by the write_word function of the swupdate object.
 * @param swupdate instance
 */
extern void yanet_write(struct swupdate*);



/**
 * This function receives a packet via YaNET 
 * ( of word length, chunksize, whatever ).
 * @param swupdate instance
 */
extern void yanet_receive(void);



/**
 * This function receives a short packet  
 * from the communication partner node via UART
 * if it is referenced by the read function of the swupdate object.
 * @param swupdate instance
 */
extern void uart_read_word(struct swupdate*);



/**
 * This function receives a packet ( containing a chunk of data ) 
 * from the communication partner node via UART
 * if it is referenced by the read function of the swupdate object.
 * @param swupdate instance
 */
extern void uart_read(struct swupdate*);




/**
 * This function receives a packet ( containing a chunk of data ) 
 * from the communication partner node via UART
 * if it is referenced by the read function of the swupdate object.
 * @param swupdate instance
 */

/**
 * This function calculates a new 16 bit CRC. It may be called 
 * in an iteration several times.
 * @param new checksum
 * @param actual checksum resulting from previous calculations
 * @param length of data input
 */
extern unsigned short crc16(unsigned short, const unsigned char *, unsigned int);



/**
 * This function loads the data temporarily from the information memory to RAM.
 * It is used for calculations ( for instance checksum ) and modifications 
 * ( as setting up secret keys, or writing the dirty bit ).
 * @param pointer to an infomem address
 * @param length of the relevant data
 */
extern void ramcpy_infomem(unsigned char *, unsigned int);




/**
 * This function decodes a data packet _in_place_.
 * @param YaNETBuffer with packet data and socket information 
 */
extern void decode_packet(struct YaNETBuffer_s*);


/**
 * This function encodes a data packet _in_place_.
 * @param YaNETBuffer with packet data and socket information 
 */
extern void encode_packet(unsigned char *,unsigned char *, int);


/** This function calculates and appends the cryptographic checksum to the packet 
*   when it is called by the sender. When called by the receiver, it removes and verifies 
*   the signature. When the signature is wrong, it sets the value of the acknwoldment sync 
*   sign to WRONG.
*   @param swupdate pointer variable to the swupdate instance
*   @param sig_op   enum type instance for either adding or removing a signature
*/
#if HASH_CHECKSUM == DAVIES_MEYER
extern void signature_packet(struct swupdate *, enum sig_op);
#endif



/**
 * This function loads the secret from the infomem.
 * The secret will be used as initial Key for the 
 * encryption or cryptographic hashing. 
 */
extern void get_key_or_initial_hash_from_infomem(void);



/**
 * This function loads the image header information 
 * from a file and sets the corresponding members 
 * in the swupdate->elf instance. It is independend from 
 * the at45 library, cause it is also called during reprogramming.
 * But it is also used in case of restoring an image stored in the 
 * external RAM, and then called by the swupdate application from program 
 * flash memory. The benefit is, that the swupdate application does not need 
 * the at45fs library.
 * @param The SPI Device
 * @param The AT45DB command to be passed to the external flash controller
 * @param An instance of the swupdate struct to store the image information in
 * @param The filenumber pointing to the image header file
 * @param The filenumber pointing to the segment data file
 */
extern inline void get_elf_info(SPIDevice_t_*, unsigned char*, struct swupdate*, int, int);



/**
 * This function does the reprogramming work. In order to erase the progam
 * memory, it must be run from RAM. Unless Simulation Mode is active, 
 * no library calls are possible because of MASS ERASE. Library calls 
 * would also falsify the code length calculation wich took place before it 
 * was loaded into RAM. 
 * The Function does not take parameters, because, when used in recovery mode, 
 * it won't be called by an application. Instead, information is retreived from  * files on the external flash.
 */
extern void __attribute__((noreturn)) program_flash(void);



/**
 * This function loads flash contents temporarily into RAM.
 * It can be used for calculations ( for instance checksum ) and modifications 
 * ( as setting up secret keys, or writing the dirty bit ) on the infomem.
 * But more important, it is necessary to copy the reprogramming routine to RAM.
 
 * @param pointer to an infomem address
 * @param length of the relevant data
 */
extern void ramcpy(const unsigned short*, unsigned short*, unsigned short);



/**
 * This function is just a dummy routine acting as an end label address for 
 * the reprogramming routine. Necessary to load the latter into RAM.
 */
extern void end_label_program_flash(void);



/**
 * This function implements the TEA encryption.
 * @param 8 Byte message
 * @param 8 Byte for the encrypted result
 * @param 16 Byte key
 */
extern void ENC_encrypt(unsigned long *v,unsigned long *w,
			unsigned long *k);
			
			
/**
 * This function implements the TEA decryption.
 * @param 8 Byte message
 * @param 8 Byte for the decrypted result
 * @param 16 Byte key
 */			
extern void DEC_decrypt(unsigned long *v,unsigned long *w,
			unsigned long *k);
			
			

/**
 * This function sets up the YaNET Socket (YaNetBuffer_s)  
 * and attaches the Event for wireless communication.
 * @param swupdate instance ( swupdate->communice )
 */			
extern void init_yanet();


#if RECEIVE_PROTOCOLL == ETHERNET
/** This function initializes the the ethernet connection. 
*   The connection properties are stored in the communction member of the 
*   swupdate instance. That allows the swupdate process to use different 
*   protocols. 
*   @param *this swupdate pointer holding a reference to the communication instance.
*   @param *con Connection_t instance that should be initialized.
*   @param *tv TranceiveVector common data structure for RX and TX mode.
*/
extern void init_ethernet(struct swupdate*, Connection_t*, TranceiveVector_t*);



/**
 * This function receives a packet
 * to the communication partner node via ethernet
 * if it is referenced by the write function of the swupdate object.
 * @param swupdate instance
 */
extern void enc28j60_read2(struct swupdate*);                            
#endif



/** This function writes the elf header information to a file on the external flash.
*   @param pointer to the swupdate instance that holds again a reference to an elf object 
*          with  the image header. 
*/
extern void save_elf_header(struct swupdate*);

extern void uart_sync_base_station(void);




/** This function writes a block of image data to a file on the external flash.
*   The lower level function is linked against the general purpose read function of the abstract 
*   level when the node is the Destination of the Update command. 
*   @param pointer to the swupdate instance that holds the input buffer. 
*/
extern void at45_write(struct swupdate*);

extern void cc1100_sync();

extern void uart_sync_pc(struct swupdate*);


/**
 * This function sends a sync packet to the base station partner node via ethernet 
 * if it is referenced by the sync function of the swupdate object.
 * @param swupdate instance
 */
extern void enc28j60_sync_pc(struct swupdate*);


/** This function deletes the files for the segment data and the image header before 
*   the node retrieves a new image that will be stored in these two files. 
*   @param pointer to the swupdate instance containing the filenumbers. 
*/
extern void setup_external_flash(struct swupdate*);




/** This function reads the filenumbers of the two files 
 *   containing the image header and the segment data of the
 *   new image.
 *   Before reprogramming, and especially after reset in the recovery case,
 *   we dont have that information in RAM. There might be several 
 *   program images on the external flash. When a program is running, 
 *   the fileforfile holds the filenumbers corresponding to that actual programm.
 *   The filenumbers will be changed right before a new installation.
 *   @param *command constant pointer to the FLASH COMMAND
 *   @param *block_counter the block containing the requested page
 *   @param page counter the pagenumber inside the block ( 0 or 1 )
 */
extern inline void file_for_file(SPIDevice_t_*, unsigned char*, int*);

#endif
